﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace InDepth2Demo.Chapter12
{
    internal static class ExtensionExample
    {
        /// <summary>
        /// 示例扩展：选择随机元素
        /// 接收一个序列和一个 Random 实例，返回序列中的一个随机元素。
        /// </summary>
        public static T RandomElement<T>(this IEnumerable<T> source, Random random)
        {
            if (source == null)                                             // 1 验证参数
            {
                throw new ArgumentNullException("source");
            }

            if (random == null)
            {
                throw new ArgumentNullException("random");
            }

            ICollection collection = source as ICollection;                 // 2 优化集合
            if (collection != null)
            {
                int count = collection.Count;
                if (count == 0)
                {
                    throw new InvalidOperationException("Sequence was empty.");
                }
                int index = random.Next(count);
                return source.ElementAt(index);                             // 用 ElementAt 进一步优化
            }

            using (IEnumerator<T> iterator = source.GetEnumerator())        // 3 处理低效的情况
            {
                if (!iterator.MoveNext())
                {
                    throw new InvalidOperationException("Sequence was empty.");
                }

                int countSoFar = 1;
                T current = iterator.Current;
                while (iterator.MoveNext())
                {
                    countSoFar++;
                    if (random.Next(countSoFar) == 0)                       // 4 有时需要取代当前的推测
                    {
                        current = iterator.Current;
                    }
                }
                return current;
            }
        }
    }
}
